/*
    Geocache: some utilities for managing and visualizing geocache information
    Copyright (C) 2008  Gary Jackson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.thegbomb.common;

import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.log4j.Logger;

public class MapIterator<D, E> implements Iterator<E> {
    static private Logger logger = Logger.getLogger(MapIterator.class);
    
    private Iterator<D> input;
    private Mapper<D, E> mapper;
    private boolean init = false;
    
    // Why bother with null?  If the input is zero length or null, then we
    // have no other value for currentIterator.
    private Iterator<E> currentIterator = null;
    
    public MapIterator(Iterator<D> input, Mapper<D, E> mapper) {
        this.input = input;
        this.mapper = mapper;
    }
    
    public void remove() {
        init();
        
        currentIterator.remove();
    }
    
    public E next() {
        init();
        
        // Make sure we have a valid iterator
        if (currentIterator != null && this.hasNext())
            return currentIterator.next();
        else
            throw new NoSuchElementException();
    }
    
    public boolean hasNext() {
        init();
        
        // Shortcut for degenerate case
        if (currentIterator == null)
            return false;
        
        // If we have a valid current iterator, shortcut to true
        if (currentIterator.hasNext())
            return true;
        
        // Else try and find a valid current iterator
        while (!currentIterator.hasNext() && input.hasNext()) {
            currentIterator = mapper.map(input.next());
        }
        
        // If the new current iterator is valid, return true
        if (currentIterator.hasNext()) {
            return true;
        } else {
            // Else null the current iterator and return false
            currentIterator = null;
            return false;
        }
    }
    
    private void init() {
        if (!init) {
            if (this.input != null && this.input.hasNext())
                this.currentIterator = this.mapper.map(this.input.next());
            init = true;
        }
    }
}